home *** CD-ROM | disk | FTP | other *** search
Lisp/Scheme | 1994-05-28 | 11.1 KB | 387 lines | [TEXT/xlsp] |
- ; Blocks World from Winston&Horn
- ; modified for XLISP and graphics by Tom Almy
-
-
- #-:classes (load "classes")
-
- ;
- ; Functions for graphic assistance
-
- (defvar *bx* 0) ; text communication region
- (defvar *by* 21)
- (defvar *gx* 50) ; Graphic region origin
- (defvar *gy* 100)
- (defvar *ymax* 349) ; height of display
- (defvar *char-width* 8) ; width of characters
- (defvar *char-height* 14) ; height of characters
- (defvar *step-size* 10) ; lcd of block widths
- (defvar *delay-time* 0.3) ; delay time in seconds
-
-
- ; Move the cursor to nearest position to graphic coordiates
- #+:math (defun setgpos (x y)
- (goto-xy (round (+ x *gx*) *char-width*)
- (round (- *ymax* y *gy*) *char-height*)))
- #-:math (defun setgpos (x y)
- (goto-xy (truncate (/ (+ x *gx*) *char-width*))
- (truncate (/ (+ (/ *char-height* 2) (- *ymax* y *gy*))
- *char-height*))))
-
- ; Move the cursor to the currently set bottom position and clear the line
- ; under it
- (defun bottom ()
- (goto-xy *bx* (+ *by* 1))
- (cleol)
- (goto-xy *bx* *by*)
- (cleol)
- (goto-xy *bx* (- *by* 1))
- (cleol)
- (color 15) ; Force color to white
- nil)
-
- ; Clear the screen and go to the bottom
- (defun cb ()
- (cls)
- (bottom))
-
-
- ; Go to graphics mode
- (defun gmode ()
- (mode 16)
- (setq *by* 21)
- (setq *ymax* 349) ; reset defaults
- (setq *char-height* 14))
-
- (defun gmode480 () ; this is for GENOA SuperEGA HiRes+
- (mode 115 115 640 480)
- (setq *ymax* 480)
- (setq *by* 21)
- (setq *char-height* 8))
-
- (defun gmode600 () ; this is for GENOA SuperEGA HiRes+
- (mode 121 121 800 600)
- (setq *by* 21)
- (setq *ymax* 600)
- (setq *char-height* 8))
-
- (defun gmodev () ; EVEREX 640x480 mode
- (setq *by* 21)
- (mode 112 0 640 480)
- (setq *ymax* 480)
- (setq *char-height* 14)
- (display-blocks))
-
- (defun gmodeVGA800 () ; this is for Video 7 FastWrite/VRAM VGA
- (mode 28421 98 800 600)
- (setq *by* 21)
- (setq *ymax* 600)
- (setq *char-height* 8)
- (display-blocks))
-
- (defun gmodeVGA (&aux dims) ; standard 640x480 VGA
- ; Modified so it will work in Windows as well
- (setq dims (mode 18))
- (setq *ymax* (1+ (fourth dims)))
- (setq *by* 9)
- #+:math (setq *char-height* (truncate (1+ (fourth dims)) (second dims)))
- #+:math (setq *char-width* (truncate (1+ (third dims)) (first dims)))
- #-:math (setq *char-height* (truncate (/ (1+ (fourth dims)) (second dims))))
- #-:math (setq *char-width* (truncate (/ (1+ (third dims)) (first dims))))
- (setq *gy* (truncate (* 2.5 *char-height*)))
- (display-blocks))
-
- ; abstract classes for ball types
-
- ; basic blocks support nothing
- (defclass basic-block (name color width height position supported-by))
-
- (defmethod basic-block :support-for () nil)
-
- (defmethod basic-block :top-location ()
- (list (+ (first position) (/ width 2))
- (+ (second position) height)))
-
- (defmethod basic-block :drawname ()
- (setgpos (+ (first position)
- (/ (- width (* *char-width* (flatc name))) 2))
- (+ (second position) (/ height 2)))
- (color color) ; For Windows, which does color text
- (princ name))
-
- (defmethod basic-block :undrawname ()
- (setgpos (+ (first position)
- (/ (- width (* *char-width* (flatc name))) 2))
- (+ (second position) (/ height 2)))
- (dotimes (i (flatc name)) (princ " ")))
-
- (defmethod basic-block :draw ()
- (color (+ color 128))
- (move (+ *gx* (first position)) (+ *gy* (second position)))
- (drawrel (1- width) 0
- 0 (1- height)
- (- 1 width) 0
- 0 (- 1 height)))
-
- ; movable-blocks can be moved
- (defclass movable-block () () basic-block)
-
- (defmethod movable-block :new-position (newpos)
- (send self :draw)
- (send self :undrawname)
- (setf position newpos)
- (send self :drawname)
- (send self :draw))
-
- ; load-bearing blocks can support other blocks, and can be moved
- (defclass load-bearing-block (support-for) () movable-block)
-
- ; we can't have multiple inheritance, so we need a separate class for table
- ; table blocks can support other blocks but cannot be moved.
-
- (defclass table-block (support-for) () basic-block)
-
- ; Specific classes for table brick wedge and ball
-
- (defclass brick () () load-bearing-block)
-
- (defclass wedge () () movable-block)
-
- (defmethod wedge :draw ()
- (color (+ color 128))
- (move (+ *gx* (first position)) (+ *gy* (second position)))
- (drawrel (1- width) 0
- (- 1 (/ width 2)) (1- height )
- (- (/ width 2) width 1) (- 1 height)))
-
- (defclass ball () () movable-block)
-
- (defmethod ball :draw ()
- (color (+ color 128))
- (let ((cx (+ (first position) (/ width 2) -1 *gx*))
- (cy (+ (second position) (/ height 2) -1 *gy*))
- (fstep (/ 3.14159 18))
- (radius (1- (/ (min width height) 2))))
- (move (+ cx radius) cy)
- (dotimes (i 36)
- (draw (truncate (+ cx (* radius (cos (* (1+ i) fstep)))))
- (truncate (+ cy (* radius (sin (* (1+ i) fstep)))))))))
-
- (defclass hand (name position grasping))
-
- (defmethod hand :top-location () position)
-
- (defmethod hand :draw ()
- (color (if grasping 143 136))
- (move (+ *gx* -7 (first position)) (+ *gy* (second position)))
- (drawrel 5 0 0 10 5 0 0 -10 5 0 0 20 -15 0 0 -20))
-
- (defmethod hand :new-position (newpos)
- (send self :draw)
- (setf position newpos)
- (send self :draw))
-
- ; define all the individual blocks
-
- (setf *blocks*
- (list
- (send table-block :new :name 'table :width 430 :height 10
- :position '(0 0) :color 7)
- (send brick :new :name 'b1 :width 40 :height 40
- :position '(0 10) :color 1)
- (send brick :new :name 'b2 :width 40 :height 40
- :position '(40 10) :color 2)
- (send brick :new :name 'b3 :width 80 :height 80
- :position '(80 10) :color 3)
- (send brick :new :name 'b4 :width 40 :height 40
- :position '(160 10) :color 4)
- (send wedge :new :name 'w5 :width 40 :height 80
- :position '(200 10) :color 5)
- (send brick :new :name 'b6 :width 80 :height 40
- :position '(240 10) :color 6)
- (send wedge :new :name 'w7 :width 40 :height 40
- :position '(320 10) :color 9)
- (send ball :new :name 'l8 :width 40 :height 40
- :position '(360 10) :color 10)
- (send brick :new :name 'b9 :width 30 :height 30
- :position '(400 10) :color 12)
- ))
-
- (dolist (l *blocks*) (set (send l :name) l))
-
- (dolist (l (rest *blocks*)) ; all blocks but the table
- (setf (send table :support-for)
- (cons l (send table :support-for))
- (send l :supported-by)
- table))
-
- (definst hand *hand* :name '*hand* :position '(0 120))
-
- (defun display-blocks ()
- (cls)
- (dolist (l *blocks*) (send l :drawname)(send l :draw))
- (send *hand* :draw)
- (bottom)
- t)
-
- (defmethod basic-block :put-on (support) ; default case is bad
- (format t
- "Sorry, the ~a cannot be moved.~%"
- name))
-
- (defmethod movable-block :put-on (support)
- (if (send self :get-space support)
- (and (send *hand* :grasp self)
- (send *hand* :move self support)
- (send *hand* :ungrasp self))
- (format t
- "Sorry, there is no room for ~a on ~a.~%"
- name
- (send support :name))))
-
- (defmethod movable-block :get-space (support)
- (or (send self :find-space support)
- (send self :make-space support)))
-
- (defmethod hand :grasp (obj)
- (unless (eq grasping obj)
- (when (send obj :support-for)
- (send obj :clear-top))
- (when grasping
- (send grasping :rid-of))
- (let ((lift (max-height self obj)))
- (send self :new-position lift)
- (pause *delay-time*)
- (send self :new-position
- (list (first (send obj :top-location)) (second lift)))
- (pause *delay-time*)
- (send self :new-position (send obj :top-location))
- (pause *delay-time*))
- (send self :draw)
- (setf grasping obj)
- (send self :draw))
- t)
-
- (defmethod hand :ungrasp (obj)
- (when (send obj :supported-by)
- (send self :draw)
- (setf grasping nil)
- (send self :draw)
- t))
-
-
- (defmethod movable-block :rid-of ()
- (send self :put-on table))
-
- (defmethod movable-block :make-space (support)
- (dolist (obstruction (send support :support-for))
- (send obstruction :rid-of)
- (let ((space (send self :find-space support)))
- (when space (return space)))))
-
- (defmethod load-bearing-block :clear-top ()
- (dolist (obstacle support-for) (send obstacle :rid-of))
- t)
-
-
- (defmethod hand :move (obj support)
- (send obj :remove-support)
- (let ((newplace (send obj :get-space support)))
- (let ((lift (max-height obj support)))
- (send obj :new-position lift)
- (send self :new-position (send obj :top-location))
- (pause *delay-time*)
- (send obj :new-position (list (first newplace) (second lift)))
- (send self :new-position (send obj :top-location))
- (pause *delay-time*)
- (send obj :new-position newplace)
- (send self :new-position (send obj :top-location))
- (pause *delay-time*)))
- (send support :add-support obj)
- t)
-
-
- ; helper function to find height necessary to move object
-
- (defun max-height (obj1 obj2)
- (let ((source (first (send obj1 :top-location)))
- (dest (first (send obj2 :top-location))))
- (let ((roof 0) (min (min source dest)) (max (max source dest)) )
- (dolist (obstacle *blocks*)
- (let ((x (send obstacle :top-location)))
- (when (and (>= (first x) min)
- (<= (first x) max)
- (> (second x) roof))
- (setf roof (second x)))))
- (list (first (send obj1 :position)) (+ 20 roof)))))
-
- #+:times (defun pause (time)
- (let ((fintime (+ (* time internal-time-units-per-second)
- (get-internal-run-time))))
- (loop (when (> (get-internal-run-time) fintime)
- (return-from pause)))))
- #-:times (defun pause () (dotimes (x (* time 1000))))
-
-
- ; remove-support-for is defined twice, for each load bearing class
-
- (defmethod load-bearing-block :remove-support-for (obj)
- (setf support-for (remove obj support-for))
- t)
-
- (defmethod table-block :remove-support-for (obj)
- (setf support-for (remove obj support-for))
- t)
-
- (defmethod movable-block :remove-support ()
- (when supported-by
- (send supported-by :remove-support-for self)
- (setf supported-by nil))
- t)
-
-
-
- (defmethod load-bearing-block :add-support (obj)
- (setf support-for
- (cons obj support-for)
- (send obj :supported-by)
- self)
- t)
-
- (defmethod table-block :add-support (obj)
- (setf support-for
- (cons obj support-for)
- (send obj :supported-by)
- self)
- t)
-
- (defmethod basic-block :add-support (obj)
- t)
-
- (defmethod movable-block :find-space (support)
- (do ((offset (- (send support :width) width)
- (- offset *step-size*)))
- ((< offset 0))
- (unless (intersections-p self offset
- (first (send support :position))
- (send support :support-for))
- (return (list (+ offset (first (send support
- :position)))
- (+ (second (send support :position))
- (send support :height)))))))
-
- (defun intersections-p (obj offset base obstacles)
- (dolist (obstacle obstacles)
- (let* ((ls-proposed (+ offset base))
- (rs-proposed (+ ls-proposed (send obj :width)))
- (ls-obstacle (first (send obstacle :position)))
- (rs-obstacle (+ ls-obstacle (send obstacle :width))))
- (unless (or (>= ls-proposed rs-obstacle)
- (<= rs-proposed ls-obstacle))
- (return t)))))
-
-
- (defun m (a b) (send a :put-on b) (bottom))
- (defun d () (display-blocks))
- (gmodeVGA)
- (d)
-